import { Color, CircleGeometry, Mesh, ShaderMaterial, Vector3 } from "three";
import Effect from "./Effect";
import RadarScanShader from "../../renderExtension/Material/shaders/chunks/RadarScanShader";
import { Point } from "../../renderExtension/types/Point";
import Const from "../../application/constants/Const";
import Events from "../../application/constants/Events";
import Helper from "../../utils/Helper";
import { App } from "../../application";

/**
 * 雷达扫描动效组件
 */
export default class RadarScan extends Effect {
    /**
     * 雷达扫描区域几何体
     */
    private circleMesh;
    private uniforms;
    /**
     * 雷达扫描区半径
     */
    public radius;
    /**
     * 雷达扫描区中心位置
     */
    public center;
   /**
     * 雷达扫描区颜色
     */
    public color;
    /**
     * 闪烁速度，单位为毫秒
     */
    public time;

     /**
     * 
     * @param cfg 配置参数
     * cfg.center 位置；
     * cfg.radius 圆半径；
     * cfg.color 颜色；
     * cfg.time 扫描速度；
     * cfg.displayOnTop 是否展示在最上层。
     * @example let RadarScan = new GE.RadarScan(cfg);
    */
    constructor(cfg) {
        super();
        this.radius = (cfg.radius === undefined) ? 50 : cfg.radius;
        this.color = (cfg.color === undefined) ? '#ff0000' : cfg.color;
        this.center = cfg.center;
        this.time = (cfg.time === undefined) ? 1000 : cfg.time;
        this.displayOnTop = (cfg.displayOnTop === undefined) ? false : cfg.displayOnTop;
        this.init();

        let scope = this;
        Helper.addPropertyListener(scope, 'radius', {
            setter: (value) => {               
                scope.uniforms.radius.value = value;
                scope.dispose();
                scope.init();
            },
            getter: () => {
                return scope.uniforms.radius.value;
            }
        });
        
        Helper.addPropertyListener(scope, 'v_color', {            
            setter: (value) => {
                scope.color = value;
                scope.uniforms.v_color.value = new Color(scope.color);
             },
            getter: () => {
                return scope.color;
            }
        });
    }

    /**
     * 设置动效组件Shader参数
    */
    private setUniforms() {
        this.uniforms = {
            v_color: { type: 'c', value: new Color(this.color) },
            time: { type: 'f', value: 0.0 },
            radius: { type: 'f', value: this.radius},
        };
        if (App.getInstance().background.fog) {
            this.uniforms.fogColor = { type: "c", value: App.getInstance().background.fog.color };
            this.uniforms.fogNear = { type: "c", value: App.getInstance().background.fog.near };
            this.uniforms.fogFar = { type: "c", value: App.getInstance().background.fog.far };
        }
    }

    /**
    * 实现效果，构建顶点、像素着色器
    */
    private init() {
        let circleRadius = this.radius;
        let circleSegment = 60;
        this.setUniforms();
        var material = new ShaderMaterial({
            uniforms: this.uniforms,
            vertexShader: RadarScanShader.getVertexShader(),
            fragmentShader: RadarScanShader.getFragmentShader(),
            transparent: true,
            fog: true,
            depthTest: false
        });

        let geo = new CircleGeometry(circleRadius, circleSegment);
        let centerVector = new Point(this.center[0], this.center[1], this.center[2]).toEPSGWeb();
        this.circleMesh = new Mesh(geo, material);
        this.circleMesh.position.set(centerVector.x, centerVector.y, centerVector.z);
        //如果让标记始终显示在矢量图层上，应同时关闭深度检测并将它的渲染顺序设置的比矢量图层大。
        //深度检测不关闭的话，无论渲染顺序设置为多少，矢量图层的建筑始终离相机更近
        if (this.displayOnTop) {
            this.circleMesh.material.depthTest = false;
            this.circleMesh.renderOrder = 99;
        }
        this.circleMesh.userData.isEffectMesh = true;
        this.circleMesh.userData.effect = this;
        this.add(this.circleMesh);
        this.register();
    }

    /**
     * 设置圆环位置参数
    */
    public setPosition(position) {
        this.circleMesh.position.set(position.x, position.y, position.z);
    }

    /**
     * 注册事件
    */
    protected register() {
        super.register();
        this.app.on(Events.Render, this.updateUniforms, this);
    }

    /**
     * 释放事件
    */
    public dispose() {
        this.app.off(Events.Render, this.updateUniforms, this);
        this.remove(this.circleMesh);
    }

    /**
     * 更新动效组件Shader参数
    */
    protected updateUniforms() {
        var now = new Date().getTime();
        var n = (now % this.time) / this.time;
        this.uniforms.time.value = n * 3.14159265359 * 2;
    }
}
